package eu.catengine.common.manager;

import java.util.HashMap;

import javax.microedition.khronos.opengles.GL10;

import android.content.res.AssetManager;
import android.graphics.Typeface;
import eu.catengine.common.iface.IDisposable;
import eu.catengine.graphic.Font;

/**
 * Manager odpowiedzialny za przechowywanie danych czcionek.
 * 
 * @author mbienkowski
 */
public class FontManager implements IDisposable
{
    private static volatile FontManager mInstance;
    private HashMap<String, HashMap<Float, Font>> mFontHashMap;
    private GL10 mGL;
    private AssetManager mAssetManager;

    private FontManager()
    {
	mFontHashMap = new HashMap<String, HashMap<Float, Font>>();
    }

    /**
     * Zwraca instanację managera.
     */
    public static FontManager getInstance()
    {
	if (mInstance == null)
	{
	    mInstance = new FontManager();
	}
	return mInstance;
    }

    /**
     * Ładuje czcionkę do managera z domyślnymi znakami. <br>
     * <br>
     * Po wczytaniu odwołujemy się do pliku wyłącznie po jego nazwie, bez
     * rozszerzenia. <br>
     * <br>
     * Znaki domyślne: <br>
     * <code>abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ
     * `1234567890-=~!@#$%^&*()_+[]\;',./{}|:"<>?</code>
     * 
     * @param pathName
     *            <code>String</code> Ścieżka pliku z katalogu "Assets/".
     * @param fontSize
     *            <code>float</code> Rozmiar czcionki.
     * @return <code>Font</code> Zwraca stworzony obiekt.
     */
    public Font loadFont(String pathName, float fontSize)
    {
	return loadFont(pathName, fontSize, "");
    }

    /**
     * Ładuje czcionkę do managera z domyślnymi oraz dodatkowymi znakami.<br>
     * <br>
     * Po wczytaniu odwołujemy się do pliku wyłącznie po jego nazwie, bez
     * rozszerzenia. <br>
     * <br>
     * Znaki domyślne: <br>
     * <code>abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ
     * `1234567890-=~!@#$%^&*()_+[]\;',./{}|:"<>?</code>
     * 
     * @param pathName
     *            <code>String</code> Ścieżka pliku z katalogu "Assets/".
     * @param fontSize
     *            <code>float</code> Rozmiar czcionki.
     * @param extraCharacters
     *            <code>String</code> Znaki dodatkowe.
     * @return <code>Font</code> zwraca stworzony obiekt.
     */
    public Font loadFont(String pathName, float fontSize, String extraCharacters)
    {
	if (pathName.equals(""))
	{
	    return null;
	}

	String[] filePathArray = pathName.split("/");
	String fileName = filePathArray[filePathArray.length - 1];

	String[] fileNameArray = fileName.split("\\.");
	String name = fileNameArray[0];

	HashMap<Float, Font> innerHashMap;

	// Sprawdzam czy czcionka zostala wczytana
	if (mFontHashMap.containsKey(name))
	{
	    // Wczytuje rozmiary wczytanych czcionek
	    innerHashMap = mFontHashMap.get(name);

	    if (innerHashMap.containsKey(innerHashMap))
	    {
		return innerHashMap.get(fontSize);
	    }
	}
	// Jesli nie to tworzę dla niej hash mapę
	else
	{
	    mFontHashMap.put(name, new HashMap<Float, Font>());
	    innerHashMap = mFontHashMap.get(name);
	}

	String characters = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ `1234567890-=~!@#$%^&*()_+[]\\;',./{}|:\"<>?" + extraCharacters;

	Font font = new Font(mGL, name, Typeface.createFromAsset(mAssetManager, pathName), fontSize, normalize(characters));

	innerHashMap.put(fontSize, font);

	return font;
    }

    /**
     * Ustawia instancję biblioteki OpenGL dla managera.
     */
    public void setGL(GL10 gl)
    {
	this.mGL = gl;
    }

    /**
     * Ustawia managera zasobów zewnętrznych dla managera.<br>
     * <br>
     * <b>Metoda wywoływana automatycznie.</b><br>
     * Nie należy wywoływać metody ręcznie.
     */
    public void setAssetManager(AssetManager assetManager)
    {
	this.mAssetManager = assetManager;
    }

    /**
     * Zwraca czcionkę o podanej nazwie i rozmiarze z managera.
     */
    public Font get(String name, float fontSize)
    {
	try
	{
	    return mFontHashMap.get(name).get(fontSize);
	}
	catch (Exception e)
	{
	    e.printStackTrace();
	}

	return null;
    }

    /**
     * Usuwa czcionkę o podanej nazwie (wszystkie rozmiary) z managera.
     */
    public void remove(String name)
    {
	try
	{
	    HashMap<Float, Font> innerHashMap = mFontHashMap.get(name);

	    for (Font f : innerHashMap.values())
	    {
		f.dispose();
	    }

	    innerHashMap.clear();

	    mFontHashMap.remove(name);
	}
	catch (Exception e)
	{
	    e.printStackTrace();
	}
    }

    /**
     * Usuwa czcionkę o podanej nazwie i rozmiarze z managera.
     */
    public void remove(String name, float fontSize)
    {
	try
	{
	    Font f = mFontHashMap.get(name).get(fontSize);

	    f.dispose();

	    mFontHashMap.get(name).remove(fontSize);
	}
	catch (Exception e)
	{
	    e.printStackTrace();
	}
    }

    /**
     * Usuwa czcionkę o podaną jako parametr z managera.
     */
    public void remove(Font object)
    {
	remove(object.getFontName(), object.getFontSize());
    }

    private String normalize(String text)
    {
	String newtext = "";

	for (int i = 0; i < text.length(); i++)
	{
	    String sub = text.substring(i, i + 1);

	    if (!newtext.contains(sub))
	    {
		newtext += sub;
	    }
	}

	return newtext;
    }

    @Override
    public void dispose()
    {
	for (HashMap<Float, Font> inner : mFontHashMap.values())
	{
	    for (Font f : inner.values())
	    {
		f.dispose();
	    }

	    inner.clear();
	}

	mFontHashMap.clear();

	mFontHashMap = null;
	mInstance = null;
    }

}
